package com.sayyi.validate.constraints.custom;

import com.sayyi.validate.valid.ValidateMapCache;
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Map;

/**
 * @author xuchuang
 * date 2021/12/31 5:28 PM
 */
public class UniqueValidator implements ConstraintValidator<Unique, Object> {

    private String cacheKey;
    private String indexKey;
    private String messageTemplate;

    public static final String UNIQUE_INDEX_KEY_SUFFIX = "_unique_index";

    public static final String UNIQUE_INDEX_MAP_KEY = "index";

    @Override
    public void initialize(Unique constraintAnnotation) {
        cacheKey = constraintAnnotation.value();
        indexKey = cacheKey + UNIQUE_INDEX_KEY_SUFFIX;
        messageTemplate = constraintAnnotation.message();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        Map<Object, Object> sets = ValidateMapCache.get(cacheKey);
        Map<Object, Object> indexMap = ValidateMapCache.get(indexKey);

        if (value == null || sets == null || indexMap == null) {
            return true;
        }

        // 更新下标
        Integer index = (Integer) indexMap.get(UNIQUE_INDEX_MAP_KEY);
        indexMap.put(UNIQUE_INDEX_MAP_KEY, index + 1);

        HibernateConstraintValidatorContext hibernateContext = context.unwrap(
                HibernateConstraintValidatorContext.class );

        // Map中不存在对应的数据，则通过验证
        final Object o = sets.get(value);
        boolean valid = o == null;
        if (valid) {
            sets.put(value, index);
        } else {
            Integer preIndex = (Integer) o;
            hibernateContext.disableDefaultConstraintViolation();
            hibernateContext.addExpressionVariable("cachedValue", preIndex);
            context.buildConstraintViolationWithTemplate(messageTemplate)
                    .addConstraintViolation();
        }
        return valid;
    }

}
